﻿using System;
using System.IO;

namespace SecureConnection.Utils
{
    public class ByteArrayReader : IDisposable
    {
        private byte[] data;
        private System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bf;

        public byte[] Data { get { return data; } }
        public int Offset { get; set; }

        public ByteArrayReader()
        {
            Initialize();
        }
        public ByteArrayReader(byte[] packetData)
        {
            Load(packetData);

            Initialize();
        }
        public ByteArrayReader(byte[] packetData, int offset, int size)
        {
            Load(packetData, offset, size);

            Initialize();
        }

        ~ByteArrayReader()
        {
            Dispose();
        }

        private void Initialize()
        {
            bf = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
        }

        public void Load(byte[] packetData)
        {
            data = packetData;
            Offset = 0;
        }

        public unsafe void Load(byte[] packetData, int offset, int size)
        {
            data = new byte[size];

            fixed (byte* ptr1 = data, ptr2 = packetData)
            {
                WinApi.memcpy(new IntPtr(ptr1), new IntPtr(ptr2 + offset), new UIntPtr((uint)size));
            }

            Offset = 0;
        }

        public byte ReadByte()
        {
            byte r = data[Offset];
            Offset++;
            return r;
        }

        public unsafe byte[] ReadBytes(int size)
        {
            byte[] r = new byte[size];

            fixed (byte* ptr1 = data, ptr2 = r)
            {
                WinApi.memcpy(new IntPtr(ptr2), new IntPtr(ptr1 + Offset), new UIntPtr((uint)size));
            }

            Offset += size;
            return r;
        }

        public short ReadShort()
        {
            short r = BitConverter.ToInt16(data, Offset);
            Offset += 2;
            return r;
        }

        public int ReadInt()
        {
            int r = BitConverter.ToInt32(data, Offset);
            Offset += 4;
            return r;
        }

        public long ReadLong()
        {
            long r = BitConverter.ToInt64(data, Offset);
            Offset += 8;
            return r;
        }

        public float ReadFloat()
        {
            float r = BitConverter.ToSingle(data, Offset);
            Offset += 4;
            return r;
        }

        public double ReadDouble()
        {
            double r = BitConverter.ToDouble(data, Offset);
            Offset += 8;
            return r;
        }

        public ushort ReadUShort()
        {
            ushort r = BitConverter.ToUInt16(data, Offset);
            Offset += 2;
            return r;
        }

        public uint ReadUInt()
        {
            uint r = BitConverter.ToUInt32(data, Offset);
            Offset += 4;
            return r;
        }

        public ulong ReadULong()
        {
            ulong r = BitConverter.ToUInt64(data, Offset);
            Offset += 8;
            return r;
        }

        public object ReadObject()
        {
            int size = ReadInt();
            MemoryStream m = new MemoryStream(data, Offset, size);
            object r = bf.Deserialize(m);
            Offset += size;
            return r;
        }

        public string ReadString()
        {
            int size = ReadInt();
            string r = System.Text.Encoding.ASCII.GetString(data, Offset, size);
            Offset += size;
            return r;
        }

        public void Dispose()
        {
            data = null;
            Offset = 0;
        }
    }
}
